package com.gbei.center.interceptor;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gbei.center.config.RequestWrapper;
import com.gbei.center.model.OpenApplication;
import com.gbei.center.oauth.mapper.AuthAccessTokenMapper;
import com.gbei.center.oauth.mapper.OpenApplicationMapper;
import com.gbei.center.oauth.mapper.OpenIpWhiteMapper;
import com.gbei.center.oauth.model.AuthAccessToken;
import com.gbei.center.utils.*;
import com.gbei.center.utils.message.ResponseInfo;
import com.gbei.center.utils.message.Result;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;


/**
 * 用于校验第三方的公共参数
 *
 */
public class CheckCommonInterceptor extends HandlerInterceptorAdapter{
    private static Logger LOGGER = LoggerFactory.getLogger(CheckCommonInterceptor.class);

    @Autowired
    private OpenApplicationMapper openApplicationMapper;

    @Autowired
    private OpenIpWhiteMapper openIpWhiteMapper;

    @Autowired
    private AuthAccessTokenMapper authAccessTokenMapper;

    @Value("${open.ip.white.enable:false}")
    private Boolean openIpWhiteEnable;

    /**
     * 校验公共参数
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //获取请求参数
        JSONObject parameterMap = JSON.parseObject(new RequestWrapper(request).getBody());

        //获取接口路径 （如 "/api/open/user/getInfo"）
        String uri = request.getRequestURI();

        Map<String, String> reqParams = JsonUtils.fromJson(parameterMap.toJSONString(),Map.class);

        LOGGER.info("@@@@@@@@@ 接口URI:{}, 参数reqParams:{}",uri, reqParams);

        //获取校验类型
        String signType = reqParams.get("signType");

        //根据接口判断签名方式是否正确
        if (uri.equalsIgnoreCase("/order/orderCommon")){
            if (!"RSA2".equalsIgnoreCase(signType)){
                return this.generateErrorResponse(response, ResponseInfo.FAILURE.toResult("接口的签名类型错误"));
            }
        }else {
            if (!"MD5".equalsIgnoreCase(signType)){
                return this.generateErrorResponse(response, ResponseInfo.FAILURE.toResult("接口的签名类型错误"));
            }
        }


        String accessToken = reqParams.get("token");

        //token校验
        if(!StringUtils.isNoneBlank(accessToken)){
            return this.generateErrorResponse(response, ResponseInfo.FAILURE.toResult("token不能为空"));
        }
        //查询数据库中的Access Token
        AuthAccessToken authAccessToken = authAccessTokenMapper.selectByAccessToken(accessToken);

        if (authAccessToken == null){
            return this.generateErrorResponse(response, ResponseInfo.INVALID_TOKEN.messageToResult());
        }

        Long savedExpiresAt = authAccessToken.getExpiresIn();
        //过期日期
        LocalDateTime expiresDateTime = DateUtils.ofEpochSecond(savedExpiresAt, null);
        //当前日期
        LocalDateTime nowDateTime = DateUtils.now();

        //如果Access Token已经失效，则返回错误提示
        if(!expiresDateTime.isAfter(nowDateTime))  {
            return this.generateErrorResponse(response,ResponseInfo.EXPIRED_TOKEN.messageToResult());
        }

        String appId = authAccessToken.getClientId();

        //判断请求Ip是否合法
        if(openIpWhiteEnable) {
            String realIp = IpUtil.getIpAddr(request);
            LOGGER.info("@@@@@@@@@@@@@@ Aspect-currentIp:{}", realIp);
            if(!"0:0:0:0:0:0:0:1".equals(realIp)) {
        	  //  List<String> ipList = IOUtils.readLines(Resources.getResourceAsStream("config/ipWhiteList.txt"), Charset.forName("utf-8"));
                List<String> ipList = openIpWhiteMapper.listIp(appId);
                if(! IPWhiteListUtil.checkIpList(realIp, ipList)) {
                    return this.generateErrorResponse(response, ResponseInfo.FAILURE.toResult("非法IP,请联系管理员"));
                }
            }
        }

        // 时间戳校验，只允许十分钟内的请求，以北京时间为准
        String timestampStr = reqParams.get("timestamp");
        if (StringUtils.isBlank(timestampStr)) {
            return this.generateErrorResponse(response, ResponseInfo.FAILURE.toResult("时间戳参数不能为空"));
        } else {
            long timestamp = Long.parseLong(timestampStr);
            //10分钟内有效
            long nowTime = Math.abs(System.currentTimeMillis());
            if (nowTime - timestamp > 600000) {
                //  return this.generateErrorResponse(response, ResponseInfo.FAILURE.toResult("时间戳参数过期"));
            }
        }

        OpenApplication openApp =  openApplicationMapper.selectByClientId(appId);

        String appSecret = openApp.getAppSecret();


        if (signType.equalsIgnoreCase("RSA2")){
            //获取公钥
            String publicKey = openApp.getSignPublicKey();
            if (null == publicKey) {
                return this.generateErrorResponse(response, ResponseInfo.FAILURE.toResult("PublicKey is Empty"));
            }

            //接口数字签名校验
            if (!GbeiRsaSignature.signCheck(reqParams, publicKey, appSecret)) {
                return this.generateErrorResponse(response, ResponseInfo.FAILURE.toResult("无效的sign"));
            }
        }

        if (signType.equalsIgnoreCase("MD5")){
            //md5校验
            if (!GbeiRsaSignature.checkMd5(reqParams,appSecret)) {
                return this.generateErrorResponse(response, ResponseInfo.FAILURE.toResult("无效的sign"));
            }
        }

        return true;
    }

    /**
     * 组装错误请求的返回
     */
    private boolean generateErrorResponse(HttpServletResponse response, Result<?> result) throws Exception {
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-type", "application/json;charset=UTF-8");
        response.getWriter().write(JsonUtils.toJson(result));
        return false;
    }

}
